﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.IO;
using LedCenter.Models;

namespace LedCenter.Models.Firmware
{
    class FirmwarePackage
    {
        int ID;
        byte[] data;
        public FirmwarePackage(int id, byte[] buffer)
        {
            ID = id;
            data = new byte[buffer.Length + 10];
            data[0] = (byte)TAG.SERVER_TAG;
            data[1] = (byte)TAG.FIRMWARE_PACKAGE_HEADER;
            BitConverter.GetBytes(id).CopyTo(data, 2);
            BitConverter.GetBytes(buffer.Length).CopyTo(data, 6);
            buffer.CopyTo(data, 10);
        }

        public byte[] Data
        {
            get
            {
                return data;
            }
        }
    }
    class FirmwareInfo
    {
        int length;
        public int Length { get { return length; } }
        int offset;
        public int Offset { get { return offset; } }
        //string version;
        //public string Version{get{return version;}}
        public FirmwareInfo(int iLength, int iOffset)
        {
            length = iLength;
            offset = iOffset;
            //version = iVersion;
        }

        public byte[] Data
        {
            get
            {
                byte[] buffer = new byte[10];
                buffer[0] = (byte)TAG.SERVER_TAG;
                buffer[1] = (byte)TAG.FIRMWARE_INFO_HEADER;
                BitConverter.GetBytes(length).CopyTo(buffer, 2);
                BitConverter.GetBytes(offset).CopyTo(buffer, 6);
                //version.ToCharArray().CopyTo(buffer,9);
                //Array.Copy(version.ToCharArray(),0, buffer, 10, version.Length);
                return buffer;
            }
        }
    }
    class BlackboxFirmware
    {
        FirmwareInfo info;
        List<FirmwarePackage> packages;
        public FirmwareInfo Info
        {
            get
            {
                return info;
            }
            set
            {
                info = value;
            }
        }
        public List<FirmwarePackage> Pakages
        {
            get
            {
                return packages;
            }
            set
            {
                packages = value;
            }
        }
        public BlackboxFirmware(string path)
        {
            HexParser parser = new HexParser();
            parser.parse(path);

            File.WriteAllBytes("C:\\out.txt", parser.data.ToArray());
            // Send Firmware Info
            info = new FirmwareInfo(parser.data.Length, parser.Offset);

            packages = new List<FirmwarePackage>();

            byte[] temp = new byte[(int)TAG.FIRMWARE_PACKAGE_LENGTH];
            int nPackages = 0;
            if (parser.data.Length % (int)TAG.FIRMWARE_PACKAGE_LENGTH == 0)
                nPackages = parser.data.Length / (int)TAG.FIRMWARE_PACKAGE_LENGTH;
            else
                nPackages = parser.data.Length / (int)TAG.FIRMWARE_PACKAGE_LENGTH + 1;
            for (int i = 0, k = 0; i < nPackages - 1; i++, k += (int)TAG.FIRMWARE_PACKAGE_LENGTH)
            {
                Array.Copy(parser.data, k, temp, 0, (int)TAG.FIRMWARE_PACKAGE_LENGTH);
                //FirmwarePackage package = 

                packages.Add(new FirmwarePackage(i, temp));
            }

            int lastBufferSize = parser.data.Length - (nPackages - 1) * (int)TAG.FIRMWARE_PACKAGE_LENGTH;
            byte[] lastBuffer = new byte[lastBufferSize];
            if (lastBufferSize != 0)
            {
                Array.Copy(parser.data, (nPackages - 1) * (int)TAG.FIRMWARE_PACKAGE_LENGTH, lastBuffer, 0, lastBufferSize);
                packages.Add(new FirmwarePackage(nPackages - 1, lastBuffer));
            }
            /*
            byte[] testbytes = new byte[9];
            testbytes[0] = 0x01;
            testbytes[1] = 0x02;
            testbytes[2] = 0x03;
            testbytes[3] = 0x04;
            testbytes[4] = 0x05;
            testbytes[5] = 0x06;
            testbytes[6] = 0x07;
            testbytes[7] = 0x08;
            testbytes[8] = 0x09;
            MakeCRC1(testbytes);*/
        }

        public void MakeCRC1(byte[] bitString)
        {

            byte poly = 0x88;
            //BitArray bitArr = new BitArray(new byte[] { poly });
            string test1 = Convert.ToString(poly, 2);
            while (true)
            {
                // get the first byte
                byte temp = bitString[0];
                string test2 = Convert.ToString(temp, 2);

                byte xorResult = (byte)(temp ^ poly);
                string test3 = Convert.ToString(xorResult, 2);

                int uIdx = 0;
                for (int j = 0; j < test3.Length; j++)
                {
                    if (test3[j] == '1')
                    {
                        uIdx = j;
                        break;
                    }
                }

                byte ret = (byte)(xorResult << uIdx | bitString[1] >> uIdx);
                string test4 = Convert.ToString((byte)(xorResult << uIdx), 2);
                string test5 = Convert.ToString(bitString[1], 2);
                string test6 = Convert.ToString(ret, 2);
            }
        }
        public BitArray MakeCRC(BitArray BitString)
        {
            BitArray crc = new BitArray(8);

            // R array = 0x10001000
            crc[0] = true;
            crc[1] = false;
            crc[2] = false;
            crc[3] = false;
            crc[4] = true;
            crc[5] = false;
            crc[6] = false;
            crc[7] = false;

            string aad = DisplayBitArray(crc);
            string bitstr = DisplayBitArray(BitString);
            int i, j, k;
            for (i = 0; i < BitString.Length; )
            {
                BitArray tempArr = new BitArray(8);
                tempArr = splitBitArray(BitString, i, 8);
                string tempArrstr = DisplayBitArray(tempArr);

                BitArray result = tempArr.Xor(crc);
                string resultstr = DisplayBitArray(result);
                for (j = 0; j < result.Length; j++)
                {
                    if (result[j] == true)
                    {
                        i += j;
                        break;
                    }

                }
                BitArray resultAtl = new BitArray(8);

                for (k = 0; k < result.Length; k++)
                {
                    if (k <= j)
                    {
                        resultAtl[k] = result[j++];
                    }
                    else
                    {
                        resultAtl[k] = BitString[8 * i + j];
                    }
                }
                string resultAtl1 = DisplayBitArray(resultAtl);
                return resultAtl;

            }
            return crc;
        }
        private BitArray splitBitArray(BitArray source, int index, int length)
        {
            BitArray result = new BitArray(length);
            for (int i = 0; i < length; i++)
            {
                result[i] = source[index + i];
            }
            return result;
        }
        private string DisplayBitArray(BitArray bitArray)
        {
            StringBuilder strbuid = new StringBuilder();
            for (int i = 0; i < bitArray.Count; i++)
            {
                bool bit = bitArray.Get(i);
                strbuid.Append(bit ? 1 : 0);
            }
            return strbuid.ToString();
        }
    }
    class HexParser
    {
        List<byte> bytearray;
        int dataOffset;

        public byte[] data
        {
            get
            {
                return bytearray.ToArray();
            }
        }
        public int Offset
        {
            get
            {
                return dataOffset;
            }
        }




        public string parse(string filepath)
        {
            string strContent = "";
            string strConverted = "";
            dataOffset = -1;
            if (File.Exists(filepath))
            {
                StreamReader hexReader = new StreamReader(filepath);

                try
                {
                    char startcode;
                    string temp = "";
                    int bytecount;
                    int address;
                    int recordtype;
                    string data;
                    int strLen = 0;
                    int unitLength = 0;
                    bytearray = new List<byte>();
                    do
                    {
                        strContent = hexReader.ReadLine();
                        strLen = strContent.Length;

                        //startcode = strContent.Substring(0,1);
                        bytecount = Convert.ToInt32(strContent.Substring(1, 2), 16);
                        address = Convert.ToInt32(strContent.Substring(3, 4), 16);
                        recordtype = Convert.ToInt32(strContent.Substring(7, 2), 16);

                        if (recordtype == 0)
                        {
                            if (dataOffset == -1)
                            {
                                dataOffset = address;
                            }
                            data = strContent.Substring(9, strLen - 11);
                            if (bytecount != 0)
                            {
                                unitLength = data.Length / bytecount;
                                for (int i = 0; i < data.Length; i += unitLength)
                                {
                                    temp = data.Substring(i, unitLength);
                                    byte value = Convert.ToByte(temp, 16);
                                    bytearray.Add(value);
                                }

                            }
                        }
                    } while (hexReader.Peek() != -1);

                    // Convert data to big endian order
                    byte tempLowbyte = 0;
                    byte tempHighbyte = 0;
                    for (int i = 0; i < bytearray.Count; i += 4)
                    {
                        tempLowbyte = bytearray[i + 3];
                        bytearray[i + 3] = bytearray[i];
                        bytearray[i] = tempLowbyte;

                        tempHighbyte = bytearray[i + 2];
                        bytearray[i + 2] = bytearray[i + 1];
                        bytearray[i + 1] = tempHighbyte;
                        /*
                        strConverted += bytearray[i].ToString() +
                            bytearray[i + 1].ToString() +
                            bytearray[i + 2].ToString() +
                            bytearray[i + 3].ToString() ;
                        if (i %2 != 0)
                        {
                            strConverted += " ";
                        }
                        else
                        {
                            strConverted += "\r\n";
                        }*/
                    }


                    return strConverted;
                }
                catch (Exception e)
                {
                    strConverted += e.Message;
                }
            }
            return strConverted;
        }
    }
}

